package com.mj.flowable.examples.controller;

import com.alibaba.fastjson.JSONObject;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.EndEvent;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.common.engine.impl.util.IoUtil;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Controller
public class DeployController {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private ProcessEngine processEngine;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private RuntimeService runtimeService;


    /**
     * 发布实例
     * @return
     */
    @RequestMapping("/deploy")
    @ResponseBody
    public String deploy()
    {
        Deployment deployment =repositoryService.createDeployment()
            .addClasspathResource("holiday-request.bpmn20.xml")
            .deploy();
        return "发布成功 id:"+deployment.getId();
    }


    /**
     * 发布实例
     * @return
     */
    @RequestMapping("/deploy2")
    @ResponseBody
    public String deploy2()
    {
        Deployment deployment =repositoryService.createDeployment()
                .addClasspathResource("expense.bpmn20.xml")
                .deploy();
        return "发布成功 id:"+deployment.getId();
    }

    /**
     * 查询流程实例
     * @param deployId
     * @return
     */
    @RequestMapping("/query/instance/{deployId}")
    @ResponseBody
    public String queryInstanceById(@PathVariable String deployId)
    {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deployId)
                .singleResult();
        return "实例名称:"+processDefinition.getName();
    }


    /**
     * 开启一个流程并且设置上下文变量
     * @return
     */
    @RequestMapping("/startAndSetVar")
    @ResponseBody
    public String startAndSetVar()
    {
        RuntimeService runtimeService = processEngine.getRuntimeService();

        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put("employee","猫南北");
        variables.put("nrOfHolidays", 1); //请假天数
        variables.put("description", "猫南北请假了");
        ProcessInstance processInstance =runtimeService.startProcessInstanceByKey("holidayRequest", variables); //holidayRequest 这个对应了resources目录下的配置文件上的id
        return "实例 名称:"+processInstance.getName()+" id:"+processInstance.getId() +" 上下文变量 "+ JSONObject.toJSONString(processInstance.getProcessVariables());
    }

    /**
     * 开启一个流程并且设置上下文变量
     * @return
     */
    @RequestMapping("/startAndSetVarByProcess")
    @ResponseBody
    public String startAndSetVarByProcess(@RequestParam String processDefineKey,@RequestParam String userId)
    {
        RuntimeService runtimeService = processEngine.getRuntimeService();

        Map<String, Object> variables = new HashMap<String, Object>();
        if("Expense".equals(processDefineKey)) {
            variables.put("taskUser", userId);
        }else if("holidayRequest".equals(processDefineKey)){
            variables.put("employee", userId);
        }
        variables.put("money",998);


        ProcessInstance processInstance =runtimeService.startProcessInstanceByKey(processDefineKey, variables); //holidayRequest 这个对应了resources目录下的配置文件上的id
        return "实例 名称:"+processInstance.getName()+" id:"+processInstance.getId() +" 上下文变量 "+ JSONObject.toJSONString(processInstance.getProcessVariables());
    }


    /**
     * 查询任务列表
     * @return
     */
    @RequestMapping("/taskList")
    @ResponseBody
    public String queryTaskList()
    {

        TaskService taskService = processEngine.getTaskService();
        List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("managers").list();
        StringBuffer buffer = new StringBuffer();
        buffer.append(" 任务数为:"+tasks.size());
        for (int i=0; i<tasks.size(); i++) {
            Task task = tasks.get(i);
            buffer.append(" [");
            buffer.append(" taskID:"+task.getId());
            buffer.append(" taskName:"+task.getName());
            buffer.append(" 任务变量:"+JSONObject.toJSONString(taskService.getVariables(task.getId())));
            buffer.append("]");
        }
        return buffer.toString();
    }



    /**
     * 查询流程历史
     * @return
     */
    @RequestMapping(value = "/history/list/{processInstanceId}",produces = "application/json;charset=UTF-8")
    @ResponseBody
    public String queryHistoryList(@PathVariable String processInstanceId)
    {
        HistoryService historyService = processEngine.getHistoryService();
        List<HistoricActivityInstance> activities =
                historyService.createHistoricActivityInstanceQuery()
                        .processInstanceId(processInstanceId)
                        .finished()
                        .orderByHistoricActivityInstanceEndTime().asc()
                        .list();
        return JSONObject.toJSONString(activities);
    }




    /**
     * 查询流程定义列表
     * @return
     */
    @RequestMapping(value = "/definition/list")
    @ResponseBody
    public String queryDefinitionList()
    {
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
                .latestVersion()//查询最后的版本
                .processDefinitionKey("holidayRequest")
                .list();
        StringBuffer lastProcessDefineVersion = new StringBuffer();
        for(ProcessDefinition processDefinition:list)
        {
            lastProcessDefineVersion.append(" 流程ID "+processDefinition.getId());
            lastProcessDefineVersion.append(" 流程名称 "+processDefinition.getName());
            lastProcessDefineVersion.append(" 流程分类 "+processDefinition.getCategory());
            lastProcessDefineVersion.append(" 流程key "+processDefinition.getKey());
        }
        return lastProcessDefineVersion.toString();
    }


    /**
     * 设置签收人
     * @return
     */
    @RequestMapping(value = "/set/candidate/{taskId}/{userId}")
    @ResponseBody
    public String setCandidateUser(@PathVariable String taskId,@PathVariable String userId)
    {
        TaskService taskService = processEngine.getTaskService();
        taskService.claim(taskId, userId);
        return "设置签收完成";
    }



    /**
     * 设置签收人
     * @return
     */
    @RequestMapping(value = "/set/assignee")
    @ResponseBody
    public String setAssigneePost(@RequestParam String taskId,@RequestParam String userId)
    {
        TaskService taskService = processEngine.getTaskService();
        taskService.setAssignee(taskId, userId);
        return "设置签收完成";
    }


    public boolean isFinished(String processInstanceId)
    {
        ProcessInstance processInstance =processEngine.getRuntimeService().createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if(processInstance.isEnded())
        {
            return true;
        }
        return false;
    }

    /**
     * 查看流程图
     * @param request
     * @param response
     */
    @RequestMapping(value = "/flowChart")
    public void flowChart(HttpServletRequest request, HttpServletResponse response,@RequestParam String processInstanceId)
    {
        // 获得当前活动的节点
        String processDefinitionId;
        // 如果流程已经结束，则得到结束节点
        if (this.isFinished(processInstanceId)) {
            HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            processDefinitionId = pi.getProcessDefinitionId();
        } else {
            // 如果流程没有结束，则取当前活动节点
            // 根据流程实例ID获得当前处于活动状态的ActivityId合集
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            processDefinitionId = pi.getProcessDefinitionId();
        }
        List<String> highLightedActivities = new ArrayList<>();

        // 获得活动的节点
        List<HistoricActivityInstance> highLightedActivityList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();
        List<String> highLightedFlows = new ArrayList<>();

        for (HistoricActivityInstance tempActivity : highLightedActivityList) {
            String activityId = tempActivity.getActivityId();
            highLightedActivities.add(activityId);
            if("sequenceFlow".equals(tempActivity.getActivityType())){
                highLightedFlows.add(tempActivity.getActivityId());
            }
        }

        // 获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        ProcessEngineConfiguration engConf = processEngine.getProcessEngineConfiguration();

        ProcessDiagramGenerator diagramGenerator = engConf.getProcessDiagramGenerator();
//		ProcessDiagramGenerator diagramGenerator = new CustomProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "bmp", highLightedActivities, highLightedFlows, engConf.getActivityFontName(),
                engConf.getLabelFontName(), engConf.getAnnotationFontName(), engConf.getClassLoader(), 1.0, true);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int length;
        try {
            out = response.getOutputStream();
            while ((length = in.read(buf)) != -1) {
                out.write(buf, 0, length);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IoUtil.closeSilently(out);
            IoUtil.closeSilently(in);
        }

    }

    /**
     * 查询已签收的任务
     * @return
     */
    @RequestMapping(value = "/assignee/list/{userId}")
    @ResponseBody
    public String queryAssigneeUser(@PathVariable String userId)
    {
        TaskService taskService = processEngine.getTaskService();
        List<Task> tasks = taskService.createTaskQuery().taskAssignee(userId).list();
        StringBuffer buffer = new StringBuffer();
        buffer.append(" 任务数为:"+tasks.size() +"\r\n");
        for (int i=0; i<tasks.size(); i++) {
            Task task = tasks.get(i);
            buffer.append(" 任务 [");
            buffer.append(" taskID:"+task.getId());
            buffer.append(" taskName:"+task.getName());
            buffer.append(" 任务变量:"+JSONObject.toJSONString(taskService.getVariables(task.getId())));
            buffer.append("]");
            buffer.append("\r\n");
        }
        return buffer.toString();

    }


    /**
     * 完成任务
     * @return
     */
    @RequestMapping(value = "/complete/{taskId}")
    @ResponseBody
    public String complete(@PathVariable String taskId)
    {
        TaskService taskService = processEngine.getTaskService();
        List<Task> tasks = taskService.createTaskQuery().taskId(taskId).active().list();
        RuntimeService runtimeService = processEngine.getRuntimeService();
        //设置顺序流的判断条件
        runtimeService.setVariable(tasks.get(0).getProcessInstanceId(),"approved",true);
        runtimeService.setVariable(tasks.get(0).getProcessInstanceId(),"outcome","通过");

        taskService.complete(taskId);
        return "完成任务";

    }



    /**
     * 转办任务
     * @return
     */
    @RequestMapping(value = "/set/owner/{taskId}/{ownerUserId}")
    @ResponseBody
    public String setOwner(@PathVariable String taskId,@PathVariable String ownerUserId)
    {
        TaskService taskService = processEngine.getTaskService();
        taskService.setOwner(taskId, "当前用户ID");
        taskService.setAssignee(taskId,ownerUserId );
        return "转办完成";
    }


    /**
     * 转办任务
     * @return
     */
    @RequestMapping(value = "/set/ownerPost")
    @ResponseBody
    public String ownerPost(@RequestParam String taskId,@RequestParam String oldAssignee,@RequestParam String ownerUserId)
    {
        TaskService taskService = processEngine.getTaskService();
        taskService.setAssignee(taskId,oldAssignee ); //原审批人
        taskService.setOwner(taskId, ownerUserId); //转办人
        return "转办完成";
    }

    /**
     * 委派任务
     * @return
     */
    @RequestMapping(value = "/set/delegate/{taskId}/{delegateUserId}")
    @ResponseBody
    public String delegate(@PathVariable String taskId,@PathVariable String delegateUserId)
    {
        TaskService taskService = processEngine.getTaskService();
        taskService.setOwner(taskId, "当前用户ID");
        taskService.delegateTask(taskId,delegateUserId );
        return "委派完成";
    }


    /**
     * 处理委派任务
     * @return
     */
    @RequestMapping(value = "/handle/delegate/{taskId}")
    @ResponseBody
    public String handleDelegate(@PathVariable String taskId)
    {
        TaskService taskService = processEngine.getTaskService();
        taskService.resolveTask(taskId, null);
        return "委派完成";
    }

}
